﻿using 飞行棋;

namespace 飞行棋
{
    class Program
    {
        static void Main(string[] args)
        {
            Game game = new();
            while (true)
            {
                switch (Game.scene)
                {
                    case E_Scene.Start:
                        game.start();
                        break;
                    case E_Scene.Play:
                        game.play();
                        break;
                    case E_Scene.Over:
                        game.over();
                        break;
                    default:
                        break;
                }
            }
        }
    }
#pragma warning disable CA1416
    class Game
    {
        public static E_Scene scene = E_Scene.Start;
        Start start_ = new();
        Play play_ = new();
        Over over_ = new();
        public static int winWidth = 50, winHeight = 30;
        public static int bufWidth = 50, bufHeight = 30;
        public static bool win;
        //int playerX = bufWidth * 3 / 4, playerY = bufHeight * 3 / 4;
        //int bossX = bufWidth / 2, bossY = bufHeight / 2;
        public Game()
        {
            Console.SetWindowSize(winWidth, winHeight);
            Console.SetBufferSize(bufWidth, bufHeight);
            Console.CursorVisible = false;
        }
        public void start()
        {
            start_.start();
        }

        public void play()
        {
            play_.play();

        }


        public void over()
        {
            over_.over();
        }

    } //可创建多个游戏实例, 支持联机功能实现
    enum E_BlockType
    {
        Normal, Stop, Boom, Tunnel, Player, Computer, Double
    }
    enum E_Scene
    {
        Start, Play, Over
    }
    enum E_Choice
    {
        Play, End
    }
    struct Pos
    {
        public int x;
        public int y;
        public E_BlockType type;
        public Pos(int x, int y, E_BlockType type = E_BlockType.Normal)
        {
            this.x = x;
            this.y = y;
            this.type = type;
        }
    }
}
class Start
{
    internal void start()
    {
        E_Choice choice = E_Choice.Play;
        //Console.WriteLine("开始场景");
        writeMenu(E_Choice.Play);
        while (Game.scene == E_Scene.Start)
        {
            switch (Console.ReadKey(true).Key)
            {
                case ConsoleKey.W:
                case ConsoleKey.UpArrow:
                    choice = E_Choice.Play;
                    writeMenu(E_Choice.Play);
                    break;
                case ConsoleKey.S:
                case ConsoleKey.DownArrow:
                    choice = E_Choice.End;
                    writeMenu(E_Choice.Play);
                    break;
                case ConsoleKey.Enter:
                case ConsoleKey.Spacebar:
                    if (choice == E_Choice.Play)
                        Game.scene = E_Scene.Play;
                    else
                        Environment.Exit(0);
                    break;
                default:
                    break;
            }
        }
    }
    public void writeMenu(E_Choice choice)
    {
        Console.Clear();
        //标题
        Console.SetCursorPosition(Game.bufWidth / 2 - 3, Game.bufHeight / 6);
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine("飞行棋");
        //选项1
        if (choice == E_Choice.Play)
            Console.ForegroundColor = ConsoleColor.Red;
        else
            Console.ForegroundColor = ConsoleColor.White;
        Console.SetCursorPosition(Game.bufWidth / 2 - 4, Game.bufHeight / 3);
        Console.WriteLine("开始游戏");
        //选项2
        if (choice == E_Choice.Play)
            Console.ForegroundColor = ConsoleColor.White;
        else
            Console.ForegroundColor = ConsoleColor.Red;
        Console.SetCursorPosition(Game.bufWidth / 2 - 4, Game.bufHeight / 2);
        Console.WriteLine("结束游戏");
        Console.ForegroundColor = ConsoleColor.White;
    }
}
class Play
{
    Pos[] poses = new Pos[80];
    int origX = Game.bufWidth / 2 - 10;
    int origY = 3;
    int medTextbox = 11; //中部文本框高度
    int botTextbox = 6; //底部文本框高度
    bool turn = true; //true玩家 false电脑
    bool doub = false; //是否在双人格子
    bool pstop = false; //是否暂停一回合
    bool cstop = false; //是否暂停一回合
    int pindex = -1, cindex = -1;
    bool change = false; //是否换位置
    internal void play()
    {
        Console.Clear();
        writeBlockAndInfo();
        writeMap();
        //行动
        Random r = new Random();
        Pos player = new Pos(origX - 2, origY, E_BlockType.Player);
        Pos computer = new Pos(origX - 2, origY, E_BlockType.Computer);
        while (Game.scene == E_Scene.Play)
        {
            Console.ReadKey(true);
            int dice = r.Next(1, 7);
            if (turn && !pstop) //player
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
                Console.Write("玩家掷出了" + dice + "点         ");
                erase(pindex);
                doub = false;
                pindex += dice;
                if (pindex >= poses.Length) //超出需要回退
                {
                    pindex = 2 * poses.Length - pindex - 2;
                }
                if (pindex == cindex) //同一位置需要处理
                {
                    doub = true;
                }
                //进行当前格子效果
                desc(ref pindex, ref cindex);
                write(pindex, cindex, change);
                turn = false;
            }
            else if (turn && pstop) //player暂停
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
                turn = false;
                pstop = false;
            }
            else if (!turn && !cstop)//computer
            {
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
                Console.Write("电脑掷出了" + dice + "点          ");
                erase(cindex);
                doub = false;
                cindex += dice;
                if (cindex >= poses.Length)
                {
                    cindex = 2 * poses.Length - cindex - 2;
                }
                if (pindex == cindex) //同一位置需要处理
                {
                    doub = true;
                }
                desc(ref cindex, ref pindex);
                write(cindex, pindex, change);
                turn = true;
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
                turn = true;
                cstop = false;
            }
            if (pindex == poses.Length - 1 || cindex == poses.Length - 1)
            {
                Game.win = !turn;
                Console.ForegroundColor = ConsoleColor.White;
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 2);
                Console.Write("                                      ");
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
                Console.Write("                                      ");
                Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
                Console.Write("游戏结束!");
                pindex = -1;
                cindex = -1;
                Thread.Sleep(1000);
                Game.scene = E_Scene.Over;
            }

        }
    }
    private void desc(ref int index, ref int oindex)
    {
        change = false;
        //判断效果
        Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 2);
        Console.Write("                          ");
        Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 2);
        switch (poses[index].type)
        {
            case E_BlockType.Normal:
                break;
            case E_BlockType.Stop:
                if (turn)
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    pstop = true;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    cstop = true;
                }
                Console.Write("暂停1回合");
                break;
            case E_BlockType.Boom:
                index -= 6;
                if (index < 0)
                    index = 0;
                if (turn)
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    pstop = true;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    cstop = true;
                }
                Console.Write("炸弹!倒退6步");
                break;
            case E_BlockType.Tunnel:
                Random r = new Random();
                int effect = r.Next(0, 3);
                if (effect == 0) //倒退
                {
                    int back = r.Next(1, 7);
                    index -= back;
                    if (index < 0)
                        index = 0;
                    if (turn)
                        Console.ForegroundColor = ConsoleColor.Cyan;
                    else
                        Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.Write("时空隧道, 倒退" + back + "步");
                }
                else if (effect == 1) //暂停
                {
                    if (turn)
                    {
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        pstop = true;
                    }
                    else
                    {
                        cstop = true;
                        Console.ForegroundColor = ConsoleColor.Magenta;
                    }
                    Console.Write("时空隧道, 暂停一回合");
                    break;
                }
                else //换位置
                {
                    change = true;
                    int temp = index;
                    index = oindex;
                    oindex = temp;
                    if (turn)
                        Console.ForegroundColor = ConsoleColor.Cyan;
                    else
                        Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.Write("时空隧道, 互换位置");
                }
                break;
            default:
                break;
        }
    }
    void write(int index, int oindex, bool change)
    {
        //画
        Console.SetCursorPosition(poses[index].x, poses[index].y);
        if (doub)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.Write("◎");
        }
        else if (turn)
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.Write("★");
        }
        else
        {
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("▲");
        }
        if (change) //换位置需要重画对方
        {
            Console.SetCursorPosition(poses[oindex].x, poses[oindex].y);
            if (doub)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write("◎");
            }
            else if (!turn)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.Write("★");
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Write("▲");
            }
        }

    }
    internal void draw(Pos pos) //画单个格子
    {
        Console.SetCursorPosition(pos.x, pos.y);
        switch (pos.type)
        {
            case E_BlockType.Normal:
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write("□");
                break;
            case E_BlockType.Stop:
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.Write("‖");
                break;
            case E_BlockType.Boom:
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write("●");
                break;
            case E_BlockType.Tunnel:
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.Write("¤");
                break;
            case E_BlockType.Player:
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.Write("★");
                break;
            case E_BlockType.Computer:
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Write("▲");
                break;
            case E_BlockType.Double:
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write("◎");
                break;
            default:
                break;
        }
    }
    private void writeMap()
    {
        //动态规划 
        //画80个格子
        //纳入一个数组pos[80
        int num = poses.Length;
        int direct = 0; //方向
        //初始格子
        Pos pos = new Pos(origX, origY);
        poses[0] = pos;
        draw(pos);
        //玩家电脑格子
        Pos pos0 = new Pos(origX - 2, origY, E_BlockType.Double);
        draw(pos0);
        //其他格子
        num--;
        while (num > 0)
        {
            if (direct == 0 && pos.x < origX + 20) //向右
            {
                pos.x += 2;
                draw(pos);
            }

            else if (direct == 0 && pos.x >= origX + 20) //向下
            {
                pos.y += 1;
                draw(pos);
                direct = 1;
            }
            else if (direct == 1) //向下
            {
                pos.y += 1;
                draw(pos);
                if (pos.x >= origX + 20)
                    direct = 2;
                else if (pos.x <= origX)
                    direct = 0;
                else
                    Console.Write("error!");
            }
            else if (direct == 2 && pos.x > origX) //向左
            {
                pos.x -= 2;
                draw(pos);
            }
            else
            {
                pos.y += 1;
                draw(pos);
                direct = 1;
            }
            poses[poses.Length - num] = pos;
            num--;
        }
        //特殊格子生成
        Random r = new Random();
        int stopNum = 6, boomNum = 2, tunnelNum = 5;
        while (stopNum > 0)
        {
            int index = r.Next(0, poses.Length - 1);
            if (poses[index].type == E_BlockType.Normal)
            {
                poses[index].type = E_BlockType.Stop;
                draw(poses[index]);
                stopNum--;
            }
        }
        while (boomNum > 0)
        {
            int index = r.Next(0, poses.Length - 1);
            if (poses[index].type == E_BlockType.Normal)
            {
                poses[index].type = E_BlockType.Boom;
                draw(poses[index]);
                boomNum--;
            }
        }
        while (tunnelNum > 0)
        {
            int index = r.Next(0, poses.Length - 1);
            if (poses[index].type == E_BlockType.Normal)
            {
                poses[index].type = E_BlockType.Tunnel;
                draw(poses[index]);
                tunnelNum--;
            }
        }
    }

    private void erase(int index)
    {
        if (index != -1)
        {
            Pos pos = poses[index];
            Console.SetCursorPosition(pos.x, pos.y);
            if (doub)
            {
                if (turn)
                {
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.Write("▲");
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.Write("★");
                }
                return;
            }
            draw(pos);
        }
        else
        {
            Console.SetCursorPosition(poses[0].x - 2, poses[0].y);
            if (turn)
            {
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Write("▲");
            }
            else
                Console.Write("  ");
        }
    }

    public void writeBlockAndInfo()
    {
        String block = "■";
        for (int i = 0; i < Game.bufWidth - 1; i++)
        {
            //边框
            Console.ForegroundColor = ConsoleColor.Red;
            Console.SetCursorPosition(i, 0);
            Console.Write(block);
            Console.SetCursorPosition(i, Game.bufHeight - 1);
            Console.Write(block);
            //中部文字框
            Console.SetCursorPosition(i, Game.bufHeight - medTextbox);
            Console.Write(block);
            //底部文字框
            Console.SetCursorPosition(i, Game.bufHeight - botTextbox);
            Console.Write(block);
            //中部文字框说明文字
            Console.SetCursorPosition(2, Game.bufHeight - medTextbox + 1);
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("□:普通格子");
            Console.SetCursorPosition(2, Game.bufHeight - medTextbox + 2);
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.Write("‖:暂停,一回合不动");
            Console.SetCursorPosition(Game.bufWidth / 2, Game.bufHeight - medTextbox + 2);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.Write("●:炸弹,倒退6格");
            Console.SetCursorPosition(2, Game.bufHeight - medTextbox + 3);
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.Write("¤:时空隧道,随机倒退,暂停,换位置");
            Console.SetCursorPosition(2, Game.bufHeight - medTextbox + 4);
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.Write("★:玩家\t");
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write("▲:电脑\t");
            Console.ForegroundColor = ConsoleColor.Green;
            Console.Write("◎:边框");
            //底部文字框说明文字
            Console.ForegroundColor = ConsoleColor.White;
            Console.SetCursorPosition(2, Game.bufHeight - botTextbox + 1);
            Console.Write("按任意键开始掷骰子");

        }
        for (int j = 1; j < Game.bufHeight - 1; j++)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.SetCursorPosition(0, j);
            Console.Write(block);
            Console.SetCursorPosition(Game.bufWidth - 2, j);
            Console.Write(block);
        }

    }
}
class Over
{
    internal void over()
    {
        Console.Clear();
        Console.SetCursorPosition(Game.bufWidth / 2 - 1, Game.bufHeight / 4);
        if (Game.win)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("胜利!");
        }
        else
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("失败!");
        }
        while (Console.KeyAvailable) //清空按键缓冲区
            Console.ReadKey(true);
        Console.ReadKey(true); // 等待用户按键
        Game.scene = E_Scene.Start;
    }
}